<!doctype html>
<html>
  <head>
    <title>Code Snippet</title>

    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <link type="text/css" rel="stylesheet" href="style.css">
	<link type="text/css" rel="stylesheet" href="css/shCore.css"></link>
	<link type="text/css" rel="stylesheet" href="css/shThemeEclipse.css"></link>
	<script language="javascript" src="js/shCore.js"></script>
	<script language="javascript" src="js/shBrushJava.js"></script>
	<script type="text/javascript">SyntaxHighlighter.all();</script> 
  </head>
  <body>

<p style="width: 600px; padding: 5px 20px; font-size: 16px;">
The code below is the version of the seat reservation code that uses Objectify. The actual code is here:
<a href="http://code.google.com/p/gaetestjig/source/browse/trunk/GaeTestJig/src/gae/testjig/ofy/dao/ODaoSeats.java">ODaoSeats.java</a>.
</p>

<script type="syntaxhighlighter" class="brush: java"><![CDATA[
	static public void reserveSeat(ChannelLogger logger, String ownerName, String seatId) throws DuplicateException {
		logger.info(ownerName+": BEGIN");
		for (int i=0;i<10;i++) {
			try {
				reserveSeatAttempt(logger, ownerName, seatId);
				logger.info(ownerName+": END");
				return; // we get here if reservation succeeds
			}
			catch (ConcurrentModificationException cme) {
				logger.info(ownerName+": EXCEPTION java.util.ConcurrentModificationException");
				// stay in the loop and try again.
			}
			// you could use another backoff algorithm here rather than 100ms each time.
			try { Thread.sleep(100); } catch (InterruptedException e) {}
		}
		logger.info(ownerName+": ABORT");
		throw new ConcurrentModificationException("failed to reserve seat "+seatId);
	}

	static private void reserveSeatAttempt(ChannelLogger logger, String ownerName, String seatId) throws DuplicateException, ConcurrentModificationException {
		logger.info(ownerName+": beginning transaction.");
		Objectify ofy = ObjectifyService.beginTransaction();
		logger.info(ownerName+": transactionId="+ofy.getTxn().getId());

		try {
			logger.info(ownerName+": test for existence of entity with seatId=" + seatId);
			Query<OSeat> testExistsQuery = ofy.query(OSeat.class).ancestor(seatsRootKey).filter("seatId =", seatId);
			OSeat exists = testExistsQuery.get();
			if ( exists != null ) {
				logger.info(ownerName+": sorry, that seat has already been taken.");
				throw new DuplicateException("seatId "+seatId+" already exists.");
			} else {
				logger.info(ownerName+": that seat has not been taken yet.");
				logger.info(ownerName+": create the seat entity with seatId=" + seatId);
				OSeat seat = new OSeat(seatsRootKey, seatId, ownerName);
				Key<OSeat> key = ofy.put(seat);
				logger.info(ownerName+": created seat. entity key = " + KeyFactory.keyToString(key.getRaw()));
				ofy.getTxn().commit(); // throws java.util.ConcurrentModificationException if entity group was modified by other thread
				logger.info(ownerName+": transaction committed.");
			}
		}
		finally {
			if (ofy.getTxn().isActive()) {
		        ofy.getTxn().rollback();
		    }
		}
	}
]]></script>


  </body>
</html>
